package cz.muni.fi.pa165.bookingmanager.dao.impl;

import cz.muni.fi.pa165.bookingmanager.entities.Room;
import cz.muni.fi.pa165.bookingmanager.exceptions.IllegalOrphanException;
import cz.muni.fi.pa165.bookingmanager.exceptions.NonexistentEntityException;
import cz.muni.fi.pa165.bookingmanager.exceptions.PreexistingEntityException;
import cz.muni.fi.pa165.bookingmanager.dao.RoomManager;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author Jiří Holuša
 */
@Stateless
public class RoomManagerImpl implements Serializable, RoomManager {
    private static final long serialVersionUID = 1L;
    
    @PersistenceContext(unitName = "BookingManagerPU")
    private EntityManager em;

    @Override
    public void createRoom(Room room) throws IllegalOrphanException, PreexistingEntityException {
        if (room == null) {
            throw new IllegalArgumentException();
        }

        if (room.getId() != null) {
            throw new IllegalOrphanException(null);
        }

        em.persist(room);
    }

    @Override
    public void updateRoom(Room room) throws IllegalOrphanException, NonexistentEntityException {
        if (room == null) {
            throw new IllegalArgumentException();
        }
        if (room.getId() == null) {
            throw new IllegalOrphanException(null);
        }

        if (em.find(Room.class, room.getId()) == null) {
            throw new NonexistentEntityException("The room with id " + room.getId() + " no longer exists.");
        }

        try {
            em.merge(room);
        } catch (IllegalArgumentException ex) {
            throw new NonexistentEntityException("The room entity no longer exists.", ex);
        }
    }

    @Override
    public void deleteRoom(Room room) throws IllegalOrphanException, NonexistentEntityException {
        if (room == null) {
            throw new IllegalArgumentException("Room cannot be null.");
        }
        if (room.getId() == null) {
            throw new IllegalOrphanException(null);
        }

        try {
            em.remove(em.merge(room));
            
        } catch (IllegalArgumentException ex) {
            throw new NonexistentEntityException("The Room entity no logner exist.", ex);
        }
    }

    @Override
    public Room getRoomById(Long id) {
        return em.find(Room.class, id);
    }

    @Override
    public Room findRoomByNumber(String number, Long hotelId) {
        try {
            Query q = em.createQuery("SELECT o FROM Room o WHERE o.roomNumber = '" + number + "'");

            return (Room) q.getSingleResult();
        } catch (NoResultException ex) {
            return null;
        }
    }

    @Override
    public List<Room> findAllHotelRooms(Long hotelId) {
        if (hotelId == null) {
            return new ArrayList<Room>();
        }

        Query q = em.createQuery("SELECT object(o) FROM Room AS o WHERE o.hotel.id = " + hotelId);

        @SuppressWarnings("unchecked")
        List<Room> rooms = q.getResultList();
        return rooms;
    }

    @Override
    public List<Room> findRoomsByPrice(BigDecimal from, BigDecimal to) {
        Query q = em.createQuery("SELECT o FROM Room o WHERE o.price >= " + from + " AND o.price <= " + to);

        @SuppressWarnings("unchecked")
        List<Room> rooms = q.getResultList();
        return rooms;
    }

    @Override
    public List<Room> findRoomsByPrice(BigDecimal from, BigDecimal to, Long hotelId) {
        Query q = em.createQuery("SELECT object(o) FROM Room AS o WHERE o.hotel.id = " + hotelId + " AND o.price >= " + from.intValue() + " AND o.price <= " + to.intValue());

        @SuppressWarnings("unchecked")
        List<Room> rooms = q.getResultList();
        return rooms;
    }

    @Override
    public List<Room> findRoomsByCapacity(int capacity) {
        Query q = em.createQuery("SELECT o FROM Room o WHERE o.capacity >= " + capacity);

        @SuppressWarnings("unchecked")
        List<Room> rooms = q.getResultList();
        return rooms;
    }

    @Override
    public List<Room> findRoomsByCapacity(int capacity, Long hotelId) {
        Query q = em.createQuery("SELECT object(o)  FROM Room AS o WHERE o.hotel.id = " + hotelId + " AND o.capacity >= " + capacity);

        @SuppressWarnings("unchecked")
        List<Room> rooms = q.getResultList();
        return rooms;
    }
}
